package auth.sso.oidc;

import static auth.ConfigUtil.*;

import auth.sso.SsoConfigs;
import java.util.Optional;
import lombok.Getter;

/** Class responsible for extracting and validating OIDC related configurations. */
@Getter
public class OidcConfigs extends SsoConfigs {

  /** Required configs */
  public static final String OIDC_CLIENT_ID_CONFIG_PATH = "auth.oidc.clientId";

  public static final String OIDC_CLIENT_SECRET_CONFIG_PATH = "auth.oidc.clientSecret";
  public static final String OIDC_DISCOVERY_URI_CONFIG_PATH = "auth.oidc.discoveryUri";

  /** Optional configs */
  public static final String OIDC_USERNAME_CLAIM_CONFIG_PATH = "auth.oidc.userNameClaim";

  public static final String OIDC_USERNAME_CLAIM_REGEX_CONFIG_PATH = "auth.oidc.userNameClaimRegex";
  public static final String OIDC_SCOPE_CONFIG_PATH = "auth.oidc.scope";
  public static final String OIDC_CLIENT_NAME_CONFIG_PATH = "auth.oidc.clientName";
  public static final String OIDC_CLIENT_AUTHENTICATION_METHOD_CONFIG_PATH =
      "auth.oidc.clientAuthenticationMethod";
  public static final String OIDC_JIT_PROVISIONING_ENABLED_CONFIG_PATH =
      "auth.oidc.jitProvisioningEnabled";
  public static final String OIDC_PRE_PROVISIONING_REQUIRED_CONFIG_PATH =
      "auth.oidc.preProvisioningRequired";
  public static final String OIDC_EXTRACT_GROUPS_ENABLED = "auth.oidc.extractGroupsEnabled";
  public static final String OIDC_GROUPS_CLAIM_CONFIG_PATH_CONFIG_PATH =
      "auth.oidc.groupsClaim"; // Claim expected to be an array of group names.
  public static final String OIDC_RESPONSE_TYPE = "auth.oidc.responseType";
  public static final String OIDC_RESPONSE_MODE = "auth.oidc.responseMode";
  public static final String OIDC_USE_NONCE = "auth.oidc.useNonce";
  public static final String OIDC_CUSTOM_PARAM_RESOURCE = "auth.oidc.customParam.resource";
  public static final String OIDC_READ_TIMEOUT = "auth.oidc.readTimeout";
  public static final String OIDC_EXTRACT_JWT_ACCESS_TOKEN_CLAIMS =
      "auth.oidc.extractJwtAccessTokenClaims";
  public static final String OIDC_PREFERRED_JWS_ALGORITHM = "auth.oidc.preferredJwsAlgorithm";

  /** Default values */
  private static final String DEFAULT_OIDC_USERNAME_CLAIM = "email";

  private static final String DEFAULT_OIDC_USERNAME_CLAIM_REGEX = "(.*)";
  private static final String DEFAULT_OIDC_SCOPE =
      "openid profile email"; // Often "group" must be included for groups.
  private static final String DEFAULT_OIDC_CLIENT_NAME = "oidc";
  private static final String DEFAULT_OIDC_CLIENT_AUTHENTICATION_METHOD = "client_secret_basic";
  private static final String DEFAULT_OIDC_JIT_PROVISIONING_ENABLED = "true";
  private static final String DEFAULT_OIDC_PRE_PROVISIONING_REQUIRED = "false";
  private static final String DEFAULT_OIDC_EXTRACT_GROUPS_ENABLED =
      "false"; // False since extraction of groups can overwrite existing group membership.
  private static final String DEFAULT_OIDC_GROUPS_CLAIM = "groups";
  private static final String DEFAULT_OIDC_READ_TIMEOUT = "5000";

  private String clientId;
  private String clientSecret;
  private String discoveryUri;
  private String userNameClaim;
  private String userNameClaimRegex;
  private String scope;
  private String clientName;
  private String clientAuthenticationMethod;
  private boolean jitProvisioningEnabled;
  private boolean preProvisioningRequired;
  private boolean extractGroupsEnabled;
  private String groupsClaimName;
  private Optional<String> responseType;
  private Optional<String> responseMode;
  private Optional<Boolean> useNonce;
  private Optional<String> customParamResource;
  private String readTimeout;
  private Optional<Boolean> extractJwtAccessTokenClaims;
  private Optional<String> preferredJwsAlgorithm;

  public OidcConfigs(final com.typesafe.config.Config configs) {
    super(configs);
    clientId = getRequired(configs, OIDC_CLIENT_ID_CONFIG_PATH);
    clientSecret = getRequired(configs, OIDC_CLIENT_SECRET_CONFIG_PATH);
    discoveryUri = getRequired(configs, OIDC_DISCOVERY_URI_CONFIG_PATH);
    userNameClaim =
        getOptional(configs, OIDC_USERNAME_CLAIM_CONFIG_PATH, DEFAULT_OIDC_USERNAME_CLAIM);
    userNameClaimRegex =
        getOptional(
            configs, OIDC_USERNAME_CLAIM_REGEX_CONFIG_PATH, DEFAULT_OIDC_USERNAME_CLAIM_REGEX);
    scope = getOptional(configs, OIDC_SCOPE_CONFIG_PATH, DEFAULT_OIDC_SCOPE);
    clientName = getOptional(configs, OIDC_CLIENT_NAME_CONFIG_PATH, DEFAULT_OIDC_CLIENT_NAME);
    clientAuthenticationMethod =
        getOptional(
            configs,
            OIDC_CLIENT_AUTHENTICATION_METHOD_CONFIG_PATH,
            DEFAULT_OIDC_CLIENT_AUTHENTICATION_METHOD);
    jitProvisioningEnabled =
        Boolean.parseBoolean(
            getOptional(
                configs,
                OIDC_JIT_PROVISIONING_ENABLED_CONFIG_PATH,
                DEFAULT_OIDC_JIT_PROVISIONING_ENABLED));
    preProvisioningRequired =
        Boolean.parseBoolean(
            getOptional(
                configs,
                OIDC_PRE_PROVISIONING_REQUIRED_CONFIG_PATH,
                DEFAULT_OIDC_PRE_PROVISIONING_REQUIRED));
    extractGroupsEnabled =
        Boolean.parseBoolean(
            getOptional(configs, OIDC_EXTRACT_GROUPS_ENABLED, DEFAULT_OIDC_EXTRACT_GROUPS_ENABLED));
    groupsClaimName =
        getOptional(configs, OIDC_GROUPS_CLAIM_CONFIG_PATH_CONFIG_PATH, DEFAULT_OIDC_GROUPS_CLAIM);
    responseType = getOptional(configs, OIDC_RESPONSE_TYPE);
    responseMode = getOptional(configs, OIDC_RESPONSE_MODE);
    useNonce = getOptional(configs, OIDC_USE_NONCE).map(Boolean::parseBoolean);
    customParamResource = getOptional(configs, OIDC_CUSTOM_PARAM_RESOURCE);
    readTimeout = getOptional(configs, OIDC_READ_TIMEOUT, DEFAULT_OIDC_READ_TIMEOUT);
    extractJwtAccessTokenClaims =
        getOptional(configs, OIDC_EXTRACT_JWT_ACCESS_TOKEN_CLAIMS).map(Boolean::parseBoolean);
    preferredJwsAlgorithm =
        Optional.ofNullable(getOptional(configs, OIDC_PREFERRED_JWS_ALGORITHM, null));
  }
}
